package com.cn.auth.config.custom.sms;

import com.cn.auth.config.JwtTokenEnhancerConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.*;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.UUID;

/**
 * @author: zhoujunming
 * @Description: 自定义 AuthorizationServerTokenServices
 * 可以实现自定义token生成等方法
 * @date: 2024/1/9 14:51
 * @email: zhoujunming@bluemoon.com.cn
 */
@Configuration
@Slf4j
public class SmsAuthorizationServerTokenServices extends DefaultTokenServices {

    @Autowired
    @Qualifier("smsTokenStore")
    private TokenStore smsTokenStore;

    @Resource(name="oauthClientDetailsService")
    private ClientDetailsService clientDetailsService;

    @Autowired
    @Qualifier("smsTokenEnhancerChain")
    private TokenEnhancerChain smsTokenEnhancerChain;


    @PostConstruct
    private void init(){
        super.setTokenStore(smsTokenStore);
        super.setClientDetailsService(clientDetailsService);
        super.setSupportRefreshToken(true);
        super.setReuseRefreshToken(true);
        super.setAccessTokenValiditySeconds(7200); //令牌默认有效期是2小时
        super.setRefreshTokenValiditySeconds(9600);//刷新令牌默认有效期
        // 令牌增强
        super.setTokenEnhancer(smsTokenEnhancerChain);
    }

    /**
     * 可自定义实现token生成实现
     * @param authentication
     * @return
     * @throws AuthenticationException
     */
    @Override
    public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {
        log.info("自定义创建token开始....................");
        OAuth2AccessToken existingAccessToken = this.smsTokenStore.getAccessToken(authentication);
        OAuth2RefreshToken refreshToken = null;
        if (existingAccessToken != null) {
            if (!existingAccessToken.isExpired()) {
                this.smsTokenStore.storeAccessToken(existingAccessToken, authentication);
                return existingAccessToken;
            }

            if (existingAccessToken.getRefreshToken() != null) {
                refreshToken = existingAccessToken.getRefreshToken();
                this.smsTokenStore.removeRefreshToken(refreshToken);
            }

            this.smsTokenStore.removeAccessToken(existingAccessToken);
        }

        if (refreshToken == null) {
            refreshToken = this.createRefreshToken(authentication);
        } else if (refreshToken instanceof ExpiringOAuth2RefreshToken) {
            ExpiringOAuth2RefreshToken expiring = (ExpiringOAuth2RefreshToken)refreshToken;
            if (System.currentTimeMillis() > expiring.getExpiration().getTime()) {
                refreshToken = this.createRefreshToken(authentication);
            }
        }

        OAuth2AccessToken accessToken = createAccessToken(authentication, refreshToken);
        this.smsTokenStore.storeAccessToken(accessToken, authentication);
        refreshToken = accessToken.getRefreshToken();
        if (refreshToken != null) {
            this.smsTokenStore.storeRefreshToken(refreshToken, authentication);
        }
        return accessToken;
    }


    private OAuth2AccessToken createAccessToken(OAuth2Authentication authentication, OAuth2RefreshToken refreshToken) {
        DefaultOAuth2AccessToken token = new DefaultOAuth2AccessToken(UUID.randomUUID().toString());
        int validitySeconds = this.getAccessTokenValiditySeconds(authentication.getOAuth2Request());
        if (validitySeconds > 0) {
            token.setExpiration(new Date(System.currentTimeMillis() + (long)validitySeconds * 1000L));
        }

        token.setRefreshToken(refreshToken);
        token.setScope(authentication.getOAuth2Request().getScope());
        return (OAuth2AccessToken)(this.smsTokenEnhancerChain != null ? this.smsTokenEnhancerChain.enhance(token, authentication) : token);
    }


    private OAuth2RefreshToken createRefreshToken(OAuth2Authentication authentication) {
        if (!this.isSupportRefreshToken(authentication.getOAuth2Request())) {
            return null;
        } else {
            int validitySeconds = this.getRefreshTokenValiditySeconds(authentication.getOAuth2Request());
            String value = UUID.randomUUID().toString();
            return (OAuth2RefreshToken)(validitySeconds > 0 ? new DefaultExpiringOAuth2RefreshToken(value, new Date(System.currentTimeMillis() + (long)validitySeconds * 1000L)) : new DefaultOAuth2RefreshToken(value));
        }
    }

}
